package com.personalink.reasoning.service;

import com.personalink.common.dto.ChatRequest;
import com.personalink.common.dto.ChatResponse;
import com.personalink.reasoning.processor.MedicalProcessor;
import com.personalink.reasoning.processor.CulinaryProcessor;
import com.personalink.reasoning.processor.EmotionalProcessor;
import com.personalink.reasoning.processor.PersonaProcessor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 核心推理服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PersonaReasoningService {
    
    private final MedicalProcessor medicalProcessor;
    private final CulinaryProcessor culinaryProcessor;
    private final EmotionalProcessor emotionalProcessor;
    private final ReactiveRedisTemplate<String, Object> redisTemplate;
    
    private static final String PERSONA_STATUS_KEY = "persona:status:";
    private static final String REASONING_STATS_KEY = "reasoning:stats";
    
    /**
     * 处理聊天请求
     */
    public Mono<ChatResponse> processChat(ChatRequest request) {
        return getCurrentPersona(request.getUserId())
                .flatMap(personaId -> {
                    PersonaProcessor processor = getProcessor(personaId);
                    return processor.processRequest(request)
                            .doOnNext(response -> updateStats(personaId, "chat"))
                            .doOnNext(response -> updatePersonaStatus(request.getUserId(), personaId));
                })
                .onErrorResume(error -> {
                    log.error("聊天处理失败", error);
                    return createErrorResponse(request, error.getMessage());
                });
    }
    
    /**
     * 流式聊天处理
     */
    public Flux<ChatResponse> processChatStream(ChatRequest request) {
        return getCurrentPersona(request.getUserId())
                .flatMapMany(personaId -> {
                    PersonaProcessor processor = getProcessor(personaId);
                    return processor.processRequestStream(request)
                            .doOnNext(response -> updateStats(personaId, "stream"))
                            .doOnComplete(() -> updatePersonaStatus(request.getUserId(), personaId));
                })
                .onErrorResume(error -> {
                    log.error("流式聊天处理失败", error);
                    return Flux.just(createErrorResponse(request, error.getMessage()).block());
                });
    }
    
    /**
     * 获取当前用户的人格状态
     */
    public Mono<Object> getPersonaStatus(String userId) {
        return redisTemplate.opsForHash()
                .entries(PERSONA_STATUS_KEY + userId)
                .collectMap(Map.Entry::getKey, Map.Entry::getValue)
                .defaultIfEmpty(createDefaultPersonaStatus());
    }
    
    /**
     * 获取推理引擎统计信息
     */
    public Mono<Object> getReasoningStats() {
        return redisTemplate.opsForHash()
                .entries(REASONING_STATS_KEY)
                .collectMap(Map.Entry::getKey, Map.Entry::getValue)
                .defaultIfEmpty(createDefaultStats());
    }
    
    /**
     * 获取当前用户的人格ID
     */
    private Mono<String> getCurrentPersona(String userId) {
        return redisTemplate.opsForHash()
                .get(PERSONA_STATUS_KEY + userId, "currentPersonaId")
                .cast(String.class)
                .defaultIfEmpty("medical-assistant"); // 默认医疗助手
    }
    
    /**
     * 根据人格ID获取对应的处理器
     */
    private PersonaProcessor getProcessor(String personaId) {
        switch (personaId) {
            case "medical-assistant":
                return medicalProcessor;
            case "culinary-expert":
                return culinaryProcessor;
            case "emotional-companion":
                return emotionalProcessor;
            default:
                log.warn("未知人格ID: {}, 使用默认医疗助手", personaId);
                return medicalProcessor;
        }
    }
    
    /**
     * 更新统计信息
     */
    private void updateStats(String personaId, String type) {
        String key = personaId + ":" + type;
        redisTemplate.opsForHash()
                .increment(REASONING_STATS_KEY, key, 1)
                .subscribe();
        
        redisTemplate.opsForHash()
                .put(REASONING_STATS_KEY, "lastUpdate", LocalDateTime.now().toString())
                .subscribe();
    }
    
    /**
     * 更新人格状态
     */
    private void updatePersonaStatus(String userId, String personaId) {
        Map<String, Object> status = new HashMap<>();
        status.put("currentPersonaId", personaId);
        status.put("lastActiveTime", LocalDateTime.now().toString());
        status.put("sessionCount", 1);
        
        redisTemplate.opsForHash()
                .putAll(PERSONA_STATUS_KEY + userId, status)
                .subscribe();
    }
    
    /**
     * 创建错误响应
     */
    private Mono<ChatResponse> createErrorResponse(ChatRequest request, String errorMessage) {
        ChatResponse response = new ChatResponse();
        response.setResponseId(UUID.randomUUID().toString());
        response.setUserId(request.getUserId());
        response.setSessionId(request.getSessionId());
        response.setPersonaId("system");
        response.setContent("抱歉，处理您的请求时出现了问题：" + errorMessage);
        response.setResponseType("error");
        response.setTimestamp(LocalDateTime.now());
        response.setProcessingTime(0L);
        
        return Mono.just(response);
    }
    
    /**
     * 创建默认人格状态
     */
    private Map<String, Object> createDefaultPersonaStatus() {
        Map<String, Object> status = new HashMap<>();
        status.put("currentPersonaId", "medical-assistant");
        status.put("lastActiveTime", LocalDateTime.now().toString());
        status.put("sessionCount", 0);
        return status;
    }
    
    /**
     * 创建默认统计信息
     */
    private Map<String, Object> createDefaultStats() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("medical-assistant:chat", 0);
        stats.put("culinary-expert:chat", 0);
        stats.put("emotional-companion:chat", 0);
        stats.put("lastUpdate", LocalDateTime.now().toString());
        return stats;
    }
}